#include "uart.h"
#include "hw/board.h"
#include <cassert>
#include <string.h>
#include <algorithm>

using namespace actor;

details::FixedString::FixedString(const char* ptr, size_t sz): size{sz} {
    strncpy(data, ptr, size);
}

void UARTActor::initialize() {
  ptr = end = nullptr;
  ready = true;
  subscribe(&UARTActor::on_log);
  subscribe(&UARTActor::on_ready);
  Parent::initialize();
}

void UARTActor::on_log(message::LogStatic &message) {
  auto sz = strlen(message.data);
  assert(sz <= details::FixedString::SZ);
  /*buff.items[0] = details::FixedString(message.data, sz);*/
  buff.put(message.data, sz);
  if (ready) {
    send_start();
  }
}

void UARTActor::send_start() {
  auto &it = buff.current();
  cli();
  ptr = it.data;
  end = it.data + it.size;
  ready = false;
  send_next(false);
  sei();
}

void UARTActor::on_ready(message::UARTReady &message) {
  buff.pop();
  if (!buff.emtpy()) {
    send_start();
  } else {
    ready = true;
  }
}

void UARTActor::send_next(bool from_interrupt) {
  bool send_ready = false;
  if (!end) {
    send_ready = true;
  } else {
    if (ptr == end) {
      send_ready = true;
    } else {
      hw::Board::send_uart(*ptr++);
    }
  }
  if (send_ready) {
    if (from_interrupt) {
      send<rl::ctx::interrupt, message::UARTReady>(0, id);
    } else {
      send<rl::ctx::thread, message::UARTReady>(0, id);
    }
  }
}
